-- Text节点处理

-- 导入响应式api
local r = require "ch8.r"

local reactive = r.reactive
local ref      = r.ref
local effect   = r.effect
local dump     = r.dump
-- print("rApi", reactive, ref, effect)


local function createRenderer(...)
    local createElement, insert, setElementText, patchProps = ...
    -- print("options", createElement, insert, setElementText,patchProps)
    -- @type fun(n1,n2,container)
    local patch;

    local function mountElement(vnode, container)
        -- type
        local el = createElement(vnode["type"])
        -- 记录创建的真实el
        vnode["el"] = el;

        -- children
        if (type(vnode.children) == "string") then
            setElementText(el, vnode["children"])
        elseif (type(vnode.children) == "table") then
            -- children子节点
            for i = 1, #vnode.children, 1 do
                patch(nil, vnode.children[i], el)
            end
        end
        -- props
        if (type(vnode.props) == "table") then
            for key, value in pairs(vnode.props) do
                patchProps(el, key, nil, value)
            end
        end
        -- parent
        el["parentNode"] = container
        insert(el, container)
    end

    local function unmount(vnode)
        local parent = vnode.el.parentNode
        if (parent) then
            for i = 1, #parent.children, 1 do
                if (parent.children[i] == vnode.el) then
                    table.remove(parent.children, i)
                end
            end
        end
    end

    local function patchChildren(n1, n2, container)
        -- children 空|string|table
        -- 2个比较有九种情况

        if (type(n2.children) == "string") then
            -- table -> string
            if (type(n1.children) == "table") then
                for i = 1, #n1.children, 1 do
                    unmount(n1.children[i])
                end
            end
            -- 空|string->string
            setElementText(container, n2.children)
        elseif (type(n2.children) == "table") then
            -- table->table
            if (type(n1.children) == "table") then
                for i = 1, #n1.children, 1 do
                    unmount(n1.children[i])
                end
                for i = 1, #n2.children, 1 do
                    patch(nil, n2.children[i], container)
                end
            else
                -- 空|string -> table
                setElementText(container, "")
                for i = 1, #n2.children, 1 do
                    patch(nil, n2.children[i], container)
                end
            end
        else
            -- table ->空
            if (type(n1.children) == "table") then
                for i = 1, #n1.children, 1 do
                    unmount(n1.children[i])
                end
                for i = 1, #n2.children, 1 do
                    patch(nil, n2.children[i], container)
                end
                -- string->空
            elseif (type(n1.children) == "string") then
                setElementText(container, "")
            end
            -- 空->空
        end

    end

    local function patchElement(n1, n2)
        n2.el = n1.el
        local el = n1.el

        -- props
        local oldProps = n1.props
        local newProps = n2.props

        for nkey, _ in pairs(newProps) do
            if (newProps[nkey] ~= oldProps[nkey]) then
                patchProps(el, nkey, oldProps[nkey], newProps[nkey])
            end
        end

        for okey, _ in pairs(oldProps) do
            if not newProps[okey] then
                patchProps(el, okey, oldProps[okey], nil)
            end
        end

        -- children
        patchChildren(n1, n2, el)
    end

    patch = function(n1, n2, container)
        -- 类型不同的
        if (n1 and n1.type ~= n2.type) then
            unmount(n1)
            n1 = nil
        end

        local newNodetype = n2.type
        if (type(newNodetype) == "string") then
            if (not n1) then
                mountElement(n2, container)
            else
                patchElement(n1, n2)
            end
        elseif (type(newNodetype) == "table") then
            -- 组件的类型处理
        end
    end


    local function render(vnode, container)
        if (vnode) then
            -- 挂载新的 比较
            patch(container._vnode, vnode, container)
        else
            -- 卸载旧的
            if (container._vnode) then
                -- 卸载
                unmount(container._vnode)
            end
        end
        -- 记录旧的
        container._vnode = vnode
    end

    return {
        render = render
    }
end

local renderer = createRenderer(
-- createElement
    function(tag)
        local tagEl = {}
        tagEl["tag"] = tag
        tagEl["attr"] = {}
        tagEl["events"] = {}
        tagEl["setAttribute"] = function(key, value)
            tagEl["attr"][key] = value
        end
        tagEl["addEventListener"] = function(name, cb)
            tagEl["events"][name] = cb
        end
        tagEl["removeEvenetListener"] = function(name)
            local nameCb = tagEl["events"][name]
            if (type(nameCb) ~= "nil") then
                tagEl["events"][name] = nil
            end
        end
        tagEl["getListener"] = function(name)
            return tagEl["events"][name]
        end
        return tagEl
    end,
    -- insert
    function(el, parent)
        if (type(parent["children"]) ~= 'table') then
            parent["children"] = {}
        end
        table.insert(parent["children"], el)
    end,
    -- setElementText
    function(el, text)
        el["text"] = text
    end,
    -- patchProps
    function(el, key, preValue, nextValue)
        if (nextValue ~= preValue) then
            if (string.match(key, "^on")) then
                -- 获取名称的事件
                local name = string.lower(string.sub(key, 3))
                local invokerCb = el.getListener(name)
                if (type(nextValue) ~= "nil") then
                    -- 有新的值
                    local cbs = {}
                    -- 注册进回调
                    if (type(nextValue) == "function") then
                        cbs = { nextValue }
                    elseif (type(nextValue) == "table") then
                        -- 合并下
                        cbs = nextValue
                    end
                    -- 挂载时间戳
                    local newCb = function(e)
                        for i = 1, #cbs, 1 do
                            local cb = cbs[i]
                            if (type(cb) == "function") then
                                cb(e)
                            end
                        end
                    end
                    el.addEventListener(name, newCb)
                elseif (type(invokerCb) ~= "nil") then
                    -- 删除旧的
                    el.removeEvenetListener(name)
                end
            else
                el.setAttribute(key, nextValue)
            end
        end
    end
);

-- print("render",renderer.render)

local container = { type = "root" }
local vnode = {
    type = 'p',
    props = {
        disabled = '',
        onContextMenu = function()
            print("onContextMenu22")
        end
    },
    children = 'test'
}
renderer.render(vnode, container)
dump(container, "container--result--1")

local newNode = {
    type = 'p',
    props = {
        class = 'foo bar baz',
        onClick = function()
            print("onContextMenu")
        end
    },
    children = nil
}

renderer.render(newNode, container)

dump(container, "container--result--2")
